import os
import re
import uuid
from datetime import timedelta

import jwt
from django.core.cache import caches
from django.db.models import Q, Prefetch
from django.db.transaction import atomic
from django.http import HttpResponse, JsonResponse
from django.shortcuts import redirect
from django.utils import timezone
from django.views.decorators.cache import cache_page
from django_filters.rest_framework import DjangoFilterBackend
from django_redis import get_redis_connection
from jwt import InvalidTokenError
from rest_framework.decorators import api_view
from rest_framework.filters import OrderingFilter
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet

from common.filters import CompanyFilterSet
from common.helpers import CustomizedPagination
from common.models import District, Job, Company, User, LoginLog, Welfare, Message
from common.serializers import DistrictSimpleSerializer, DistrictDetailSerializer, JobDetailSerializer, \
    CompanySimpleSerializer, CompanyDetailSerializer
from common.utils import gen_qrcode, make_sha256_digest, get_ip_address, make_md5_digest, gen_mobile_code, \
    send_sms_by_luosimao
from zhipin.settings import SECRET_KEY

MAX_PHOTO_SIZE = 2.5 * 1024 * 1024


def show_index(request):
    return redirect('/static/html/index.html')


TEL_PATTERN = re.compile(r'1[3-9]\d{9}')


@api_view(('GET',))
def get_mobile_code(request, tel):
    """获取短信验证码
    :param tel: 手机号
    """
    if TEL_PATTERN.fullmatch(tel):
        if caches['default'].get(f'zhipin:common:block:{tel}'):
            data = {'code': 20004, 'msg': '请不要在60秒以内重复发送短信验证码'}
        else:
            code = gen_mobile_code()
            send_sms_by_luosimao.delay(tel, f'您的短信验证码是{code}，打死也不能告诉别人哟！【Python小课】')
            caches['default'].set(f'zhipin:common:block:{tel}', code, 60)
            caches['default'].set(f'zhipin:common:valid:{tel}', code, 600)
            data = {'code': 20000, 'msg': '短息发送成功!'}
    else:
        data = {'code': 20003, 'msg': '请输入有效的手机号码!'}
    return Response(data)


@api_view(('POST',))
def upload(request):
    """上传图片"""
    file_obj = request.FILES.get('photo')
    if file_obj and len(file_obj) < MAX_PHOTO_SIZE:
        file_name = make_md5_digest(file_obj.file)
        file_ext = os.path.splitext(file_obj.name)[1]
        full_name = f'{file_name}{file_ext}'
        # upload_stream_to_qiniu(file_obj.file, full_name, len(file_obj))
        # POOL.submit(upload_stream_to_qiniu, BytesIO(file_obj.file.getvalue()), full_name, len(file_obj))
        return Response({'code': 30000, 'msg': '文件已上传', 'url': f'http://qboymizkv.bkt.clouddn.com/{full_name}'})
    else:
        return Response({'code': 30001, 'msg': '文件大小超过2.5M'})


def show_qrcode(request):
    uuid_string = uuid.uuid1().hex
    redis_cli = get_redis_connection()
    redis_cli.set(uuid_string, '', ex=120)
    return JsonResponse({'uuid': uuid_string})


def show_qrimg(request):
    uuid_string = request.GET.get('uuid')
    if uuid_string:
        data = gen_qrcode(uuid_string)
        return HttpResponse(data, content_type='image/png')


@api_view(('POST', ))
def scan_qrcode(request):
    uuid_string = request.data.get('uuid')
    # user_token = request.data.get('token')
    redis_cli = get_redis_connection()
    if redis_cli.exists(uuid_string):
        try:
            # payload = jwt.decode(user_token, SECRET_KEY)
            # print(payload)
            result = {'code': 50000, 'msg': '扫码登录已完成'}
        except InvalidTokenError:
            result = {'code': 50002, 'msg': '用户令牌已失效请重新登录'}
        else:
            redis_cli.delete(uuid_string)
    else:
        result = {'code': 50001, 'msg': '二维码已经失效'}
    return Response(result)


@api_view(('GET',))
# @authentication_classes((LoginRequiredAuthentication, ))
@cache_page(timeout=365 * 86400)
def show_provinces(requests):
    """获取省级行政区域"""
    queryset = District.objects.filter(parent=0).only('name')
    serializer = DistrictSimpleSerializer(queryset, many=True)
    return Response(serializer.data)


@api_view(('GET',))
# @authentication_classes((LoginRequiredAuthentication, ))
@cache_page(timeout=3600)
def show_district(request, distid):
    """获取行政区域详情
    :param distid: 行政区域编号
    """
    district = District.objects.filter(id=distid).defer('parent').first()
    serializer = DistrictDetailSerializer(district)
    return Response(serializer.data)


# @api_view(('GET',))
# @cache_page(timeout=30 * 86400)
# def show_hot_cities(request):
#     queryset = District.objects.filter(is_hot=True).only('name')
#     serializer = DistrictSimpleSerializer(queryset, many=True)
#     return Response(serializer.data)


class HotCitiesView(ListAPIView):
    """热门城市
    get:
       获取热门城市
    """
    queryset = District.objects.filter(is_hot=True).only('name')
    serializer_class = DistrictSimpleSerializer
    # authentication_classes = (LoginRequiredAuthentication, )


class CompanyViewSet(ModelViewSet):
    """公司视图集
    list:
        获取公司列表
    retrieve:
        获取公司详情
    create:
        新增公司信息
    update:
        更新公司信息（全量）
    partial_update:
        更新公司信息（部分）
    delete:
        删除公司信息
    """
    queryset = Company.objects.all() \
        .select_related('industry_category') \
        .prefetch_related(
            Prefetch('welfares', queryset=Welfare.objects.only('name'))
        ) \
        .defer('full_name', 'start_work_time', 'end_work_time',
               'overtime_work', 'day_off', 'editor')
    serializer_class = CompanySimpleSerializer
    pagination_class = CustomizedPagination
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filterset_class = CompanyFilterSet
    # filter_fields = (
    #     'short_name', 'full_name', 'industry_category',
    #     'financing_stage', 'staff_size'
    # )
    ordering = ('id',)
    ordering_fields = ('staff_size', 'overtime_work',)

    # authentication_classes = (LoginRequiredAuthentication, )

    # def get_permissions(self):
    #     if self.request.method == 'GET':
    #         return ()
    #     return (BossPermission, )

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return CompanySimpleSerializer
        return CompanyDetailSerializer


class JobViewSet(ModelViewSet):
    """招聘信息视图集
    list:
        获取招聘信息列表
    retrieve:
        获取招聘信息详情
    create:
        新增招聘信息
    update:
        更新招聘信息（全量）
    partial_update:
        更新招聘信息（部分）
    delete:
        删除招聘信息
    """
    queryset = Job.objects.all()
    serializer_class = JobDetailSerializer
    pagination_class = CustomizedPagination

    def get_queryset(self):
        queryset = Job.objects.all() \
            .select_related('district', 'company', 'user') \
            .order_by('-pub_date')
        keyword = self.request.GET.get('keyword', None)
        if keyword:
            queryset = queryset.filter(
                Q(company__short_name__contains=keyword) |
                Q(company__full_name__contains=keyword) |
                Q(job_name__contains=keyword)
            )
        minsal = self.request.GET.get('minsal', None)
        if minsal:
            queryset = queryset.filter(min_salary__gte=minsal)
        maxsal = self.request.GET.get('maxsal', None)
        if maxsal:
            queryset = queryset.filter(max_salary__lte=maxsal)
        fstage = self.request.GET.get('fstage', None)
        if fstage:
            queryset = queryset.filter(company__financing_stage=fstage)
        distid = self.request.GET.get('distid', None)
        if distid:
            queryset = queryset.filter(district__id=distid)
        return queryset


@api_view(('POST', ))
def login(request):
    """登录（创建用户身份令牌）"""
    username = request.data.get('username')
    password = request.data.get('password')
    if username and password:
        password = make_sha256_digest(password)
        user = User.objects.filter(
            username=username, password=password, is_locked=False
        ).only('is_boss').first()
        if user:
            payload = {
                'userid': user.id,
                'isboss': user.is_boss,
                'exp': timezone.now() + timedelta(days=1)
            }
            token = jwt.encode(payload, SECRET_KEY).decode()
            result = {'code': 10000, 'msg': '登录成功', 'token': token}
            with atomic():
                user.last_visit = timezone.now()
                user.save(insert=False)
                login_log = LoginLog()
                login_log.user = user
                login_log.login_time = timezone.now()
                login_log.ip_address = get_ip_address(request)
                login_log.save()
        else:
            result = {'code': 10001, 'msg': '用户名或密码错误'}
    else:
        result = {'code': 10002, 'msg': '请输入有效的用户名和密码'}
    return Response(result)
